/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "drv_serial.h"
#include <string.h>
#include <stdbool.h>
#include "drv_pin.h"
#include "drv_led.h"

#define UART4_TX_BUFFER_SIZE 256
#define UART4_RX_BUFFER_SIZE 256

// struct rt_semaphore tx4_sem;
uint16_t tx4_size;
volatile bool tx4_busy = 0;

uint8_t uart4_tx_buffer[UART4_TX_BUFFER_SIZE];//DMA, ringbuffer 共用缓冲。 DMA 读出，ringbuffer 写入
uint8_t uart4_rx_buffer[UART4_RX_BUFFER_SIZE];//DMA, ringbuffer 共用缓冲。 DMA 写入，ringbuffer 读出
struct rt_ringbuffer rx4_ringbuffer = {
    .buffer_ptr = uart4_rx_buffer,
    .read_mirror = 0,
    .read_index = 0,
    .read_mirror = 0,
    .write_index = 0,
    .buffer_size = UART4_RX_BUFFER_SIZE
};
struct rt_ringbuffer tx4_ringbuffer = {
    .buffer_ptr = uart4_tx_buffer,
    .read_mirror = 0,
    .read_index = 0,
    .write_mirror = 0,
    .write_index = 0,
    .buffer_size = UART4_TX_BUFFER_SIZE
};


/**
 * @brief 计算缓冲区中没有发送的数据，如果缓冲区中有数据，则启动DMA发送
 *
 * @return int
 */
int tx4_send_buffer(void)
{
    if (tx4_ringbuffer.read_index <= tx4_ringbuffer.write_index)
    {
        /**缓冲未满，全部发送 */
        /** |---------Read----[data]-----Write-----------| */
        tx4_size = tx4_ringbuffer.write_index - tx4_ringbuffer.read_index;
    }
    else
    {
        /**缓冲已满，先发一部分，DMA中断接手剩余部分 */
        /**发送完成后，Read就回到Write左边了，也就是未满状态！环形缓冲转起来了！*/
        /** |----[data]-----Write-----Read----[data]-----| */
        tx4_size = tx4_ringbuffer.buffer_size - tx4_ringbuffer.read_index;
    }
    if (tx4_size > 0)
    {
        // rt_kprintf("tx4_size=%d\n", tx4_size);
        /**DMA发送 */
        tx4_busy = 1;
        DMA2_CHANNEL5->maddr = (uint32_t)tx4_ringbuffer.buffer_ptr + tx4_ringbuffer.read_index;//start address + read index
        DMA2_CHANNEL5->dtcnt = tx4_size;
        dma_channel_enable(DMA2_CHANNEL5, TRUE);
    }
    return tx4_size;
}
/**
 * @brief  把数据写入到缓冲区，如果DMA没有在忙，则启动DMA发送，
 * DMA会连续在发送，直到缓冲区为空
 *
 * @param buf
 * @param size
 * @return int
 */
int uart4_write(uint8_t *buf, rt_size_t size)
{
    if(tx4_ringbuffer.write_mirror != tx4_ringbuffer.read_mirror)
    {
        if(tx4_ringbuffer.write_index + size > tx4_ringbuffer.read_index)//buffer overflow
        {
            while(tx4_busy)//wait for DMA to send data
            {
                rt_thread_delay(1);
            }
        }
    }
    /**先把数据写入到缓冲区 */
    rt_ringbuffer_put(&tx4_ringbuffer, buf, size);
    /**如果DMA没有在忙，则启动DMA发送 */
    if (!tx4_busy)
    {
        return tx4_send_buffer();
    }
    return 0;
}
/**
 * @brief  从缓冲区中读取数据
 *
 * @param buf
 * @param size
 * @return int
 */
int uart4_read(uint8_t *buf, rt_size_t size)
{
    return rt_ringbuffer_get(&rx4_ringbuffer, buf, size);
}
/**
 * @brief 缓冲区中有多少数据未读取
 *
 * @return int16_t
 */
int16_t uart4_get_rx_data_len(void)
{
    return rt_ringbuffer_data_len(&rx4_ringbuffer);
}
uint8_t uart4_getByte(void)
{
    uint8_t ch;
    if(uart4_read(&ch, 1) == 1)
    {
        return ch;
    }
    return -1;
}
char uart4_getc(void)
{
    uint8_t ch;
    if(uart4_read(&ch, 1) == 1)
    {
        return ch;
    }
    return -1;
}
/**
 * @brief  DMA发送完成中断。
 * @param  none
 * @retval none
 */
void DMA2_Channel4_5_IRQHandler(void)
{
    rt_enter_critical();
    if (dma_interrupt_flag_get(DMA2_FDT5_FLAG))
    {
        tx4_busy = 0;
        dma_flag_clear(DMA2_FDT5_FLAG);
        dma_channel_enable(DMA2_CHANNEL5, FALSE);
        tx4_ringbuffer.read_index += tx4_size;
        if (tx4_ringbuffer.read_index >= tx4_ringbuffer.buffer_size)
        {
            //下一圈
            tx4_ringbuffer.read_mirror = ~tx4_ringbuffer.read_mirror;
            tx4_ringbuffer.read_index = 0;
        }
        /**NOTE 如果缓冲区中还有数据，继续发送 */
        tx4_send_buffer();
    }
    rt_exit_critical();
}

void DMA2_Channel3_IRQHandler(void)
{
    rt_enter_critical();
    if (dma_interrupt_flag_get(DMA2_FDT3_FLAG))
    {
        dma_flag_clear(DMA2_FDT3_FLAG);
        dma_channel_enable(DMA2_CHANNEL3, false);
        /**NOTE DMA不重置的话，计数就不会重置，接收内存地址也会继续增加 */
        /**NOTE DMA传输完成中断，说明缓冲已满，从头开始 */
        rx4_ringbuffer.write_index = 0;
        rx4_ringbuffer.write_mirror = ~rx4_ringbuffer.write_mirror;
        /**NOTE 重新接收 */
        DMA2_CHANNEL3->maddr = (uint32_t)uart4_rx_buffer;
        dma_data_number_set(DMA2_CHANNEL3, UART4_RX_BUFFER_SIZE);
        dma_channel_enable(DMA2_CHANNEL3, true);
        // rt_kprintf("write_index dma:%d \n", rx4_ringbuffer.write_index);
    }
    rt_exit_critical();
}
/**
 * @brief  UART4 空闲中断，主要是为了避免DMA完全接收完的时间太久，
 * 所以使用空闲中断来及时更新接收到的数据长度
 *
 */
void UART4_IRQHandler(void)
{
    rt_enter_critical();
    if (usart_interrupt_flag_get(UART4, USART_IDLEF_FLAG))
    {
        usart_flag_clear(UART4, USART_IDLEF_FLAG);
        usart_data_receive(UART4);
        /**NOTE 使用IDLE中断来更新接收到的数据长度 */
        /**NOTE DMA向下计数，剩余多少即是接收了多少 */
        /**NOTE DMA完成中断会必须要优先于空闲中断，并先将DMA计数重置 */
        /**NOTE |MAX------[DATA]---DMA_CNT-------0| */
        /**NOTE |0--------[DATA]---Write-------MAX| */
        uint16_t rxCnt = UART4_RX_BUFFER_SIZE - dma_data_number_get(DMA2_CHANNEL3);
        rx4_ringbuffer.write_index = rxCnt;
        // rt_kprintf("write_index uart:%d \n", rx4_ringbuffer.write_index);
    }
    rt_exit_critical();
}


/**
 * @brief  config usart
 * @param  none
 * @retval none
 */
void uart4_configuration(void)
{
    gpio_init_type gpio_init_struct;

    /* enable the uart4 and gpio clock */
    crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_UART4_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart2 tx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_4;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOF, &gpio_init_struct);

    /* configure the usart2 rx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_5;
    gpio_init_struct.gpio_pull = GPIO_PULL_UP;
    gpio_init(GPIOF, &gpio_init_struct);

    gpio_pin_remap_config(UART4_GMUX_0001, TRUE);

    /* configure usart2 param */
    usart_init(UART4, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(UART4, TRUE);
    usart_receiver_enable(UART4, TRUE);
    usart_dma_transmitter_enable(UART4, TRUE);
    usart_dma_receiver_enable(UART4, TRUE);
    usart_interrupt_enable(UART4, USART_IDLE_INT, TRUE);
    nvic_irq_enable(UART4_IRQn, 1, 1);
    usart_enable(UART4, TRUE);

    // rt_sem_init(&tx4_sem, "tx4_sem", 0, 0);
}

/**
 * @brief  config dma for usart2 and usart3
 * @param  none
 * @retval none
 */
void dma2_configuration(void)
{
    dma_init_type dma_init_struct;

    /* enable dma1 clock */
    crm_periph_clock_enable(CRM_DMA2_PERIPH_CLOCK, TRUE);

    /* dma1 channel1 for uart4 tx configuration */
    dma_reset(DMA2_CHANNEL5);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = UART4_TX_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)uart4_tx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&UART4->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA2_CHANNEL5, &dma_init_struct);

    /* enable transfer full data interrupt */
    dma_interrupt_enable(DMA2_CHANNEL5, DMA_FDT_INT, TRUE);

    /* dma2 channel4\5 interrupt nvic init */
    nvic_irq_enable(DMA2_Channel4_5_IRQn, 0, 0);

    /* config flexible dma for usart2 tx */
    // dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_UART1_TX);

    /* dma1 channel3 for uart4 rx configuration */
    dma_reset(DMA2_CHANNEL3);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = UART4_RX_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)uart4_rx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&UART4->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA2_CHANNEL3, &dma_init_struct);

    /* enable transfer full data interrupt */
    dma_interrupt_enable(DMA2_CHANNEL3, DMA_FDT_INT, TRUE);

    /* dma1 channel3 interrupt nvic init */
    nvic_irq_enable(DMA2_Channel3_IRQn, 0, 0);

    /* config flexible dma for usart2 rx */
    // dma_flexible_config(DMA1, FLEX_CHANNEL3, DMA_FLEXIBLE_UART1_RX);

    dma_channel_enable(DMA2_CHANNEL3, TRUE); /* uart4 rx begin dma receiving */
}
void rt_hw_uart4_init(void)
{
    uart4_configuration();
    dma2_configuration();
    // led_pins_init();
}
void uart4_printf(const char *fmt, ...)
{
    va_list args;
    rt_size_t length;
    static char rt_log_buf[RT_CONSOLEBUF_SIZE];

    va_start(args, fmt);
    /* the return value of vsnprintf is the number of bytes that would be
     * written to buffer had if the size of the buffer been sufficiently
     * large excluding the terminating null byte. If the output string
     * would be larger than the rt_log_buf, we have to adjust the output
     * length. */
    length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
    if (length > RT_CONSOLEBUF_SIZE - 1)
        length = RT_CONSOLEBUF_SIZE - 1;
#ifdef RT_USING_DEVICE
    if (_console_device == RT_NULL)
    {
        rt_hw_console_output(rt_log_buf);
    }
    else
    {
        rt_uint16_t old_flag = _console_device->open_flag;

        _console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
        rt_device_write(_console_device, 0, rt_log_buf, length);
        _console_device->open_flag = old_flag;
    }
#else
    // rt_hw_console_output(rt_log_buf);
    uart4_write((uint8_t *)rt_log_buf, length);
#endif
    va_end(args);
}
